#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

// 实现一个网络计算器

#define SEPA "??"
#define SEPA_LEN strlen(SEPA)
#define SPACE " "
#define SPACE_LEN strlen(SPACE)

// 是否有自己定义序列化和反序列化, 如果没有, 那么就使用 json 库中所提供的
// #define SELF_SERIALIZE 1


// 发送数据前的处理
// 再加上报头等其他信息, 加密...
// 在序列化后的字节流前面加上长度和分隔符
std::string encode(std::string& in, std::size_t len)
{
    // 加密成：len\r\nexitcode_ result_\r\n
    std::string encode_str = std::to_string(len);
    encode_str += SEPA;
    encode_str += in;
    encode_str += SEPA;
    return encode_str;
}

// 处理收到的数据
// 首先：必须有长度字段, 并且长度和实际长度必须一致
// 满足就返回有效载荷, 这里的 len 是一个输出型参数
// 并且使用 \r\n 来当做分隔符, 字符串的整体长度放在最前面
// 也就是 strlen\r\nxxxxx\r\n , 也就是说每一段数据后面都有 \r\n

// strlen\r\nxxxxx\r\n   ...
// 判断是否有分隔符, 判断“正文”长度是否 > 指明的长度
// 将第一段有效数据提取出来并剔除
std::string decode(std::string& in, int* len)
{
    // 1. 首先得有分隔符
    std::size_t pos = in.find(SEPA);
    *len = 0;
    if (pos == std::string::npos) // 没有分隔符
    {
        return "";
    }
    // 2. 有长度, 提取
    std::string len_str = in.substr(0, pos);
    int tempLen = atoi(len_str.c_str());
    int remain = in.size() - pos - 2 * SEPA_LEN; // 剩下的长度
    if (remain < tempLen)  // 如果剩余的长度  <  报文中指明的长度
    {
        return "";
    }
    // 3. 至此, 确保有完整的报文结构
    *len = tempLen;
    //    提取出 strlen\r\nxxxxx\r\n   ...
    std::string package = in.substr(pos + SEPA_LEN, tempLen);
    // 4. 剔除当前已经处理好的报文 xxxx\r\n
    int rmlen = tempLen + package.size() + 2 * SEPA_LEN;
    in.erase(0, rmlen);
    return package;
}

class Request
{
public:
    int leftop_;
    int rightop_;
    char op_;
    Request(int x = 0, int y = 0, char z = 0)
        : leftop_(x)
        , rightop_(y)
        , op_(z)
    {}

    // 序列化, 将结构化的数据转化成字符串
    // 这时候 Request 已经是完整的结构体
    // 将结构体华序列化成 leftop op rightop
    void serialize(std::string* out)
    {
#ifdef SELF_SERIALIZE
        *out = std::to_string(leftop_) + SPACE + op_ + SPACE + std::to_string(rightop_);
#else
        // json 的序列化
        // 先定义一个 Value 对象, 是一个万能对象
        // json 是基于 key-value 的
        // 并且有两套操作方法
        // 序列化的时候, 会将所有的数据内容转化成字符串
        Json::Value root;
        // 键是 结构体中的成员
        root["leftop"] = leftop_;
        root["rightop"] = rightop_;
        root["op"] = op_;
        // 开始序列化
        // Json::FastWriter fastwr;
        // 以下这种可读性更强
        Json::StyledWriter wr;
        // 将序列化后的数据返回
        *out = wr.write(root);
#endif
    }

    // 反序列化, 将字符串风格的数据转化成结构化的数据
    // 根据序列化, 运算符前后都有空格, 可以重新反序列化成结构体
    bool deserialize(std::string& in)
    {
#ifdef SELF_SERIALIZE
        int space_1 = in.find(SPACE);
        // 不满足要求, 丢弃这个报文
        if (space_1 == std::string::npos) 
            return false;

        int space_2 = in.rfind(SPACE); // 找第二个空格
        if (space_2 == std::string::npos)
            return false;

        int leftop = atoi(in.substr(0, space_1).c_str());
        int rightop = atoi(in.substr(space_2 + SPACE_LEN).c_str());

        std::string op = in.substr(space_1 + SPACE_LEN, space_2 - space_1 - SPACE_LEN); // 提取操作符
        if (op.size() != 1)
        {
            std::cout << "操作符长度并不为 1" << std::endl;
            return false;
        }

        leftop_ = leftop;
        rightop_ = rightop;
        op_ = op[0];
#else
    // json 
    Json::Value root;
    Json::Reader rd;
    // 将 序列化后的数据传入, 带上 root 一起 
    // 完成解析
    rd.parse(in, root);

    // 然后将数据读取出来, 安装其对应的类型来提取
    leftop_ = root["leftop"].asInt();
    rightop_ = root["rightop"].asInt();
    op_ = root["op"].asInt();
#endif
        return true;
    }

    void debug() { std::cout << "left [op] right --> " << leftop_ << " " << op_ << " " << rightop_ << std::endl; }
};

class Response
{
public:
    int exitcode_; // 退出码
    int result_; // 计算结果
    Response(int code = 0, int res = 0)
        : exitcode_(code)
        , result_(res)
    {}

    // 序列化, 输出型参数, 会返回成功序列化后的结果
    // out 是输出型参数
    // 序列化, 成员之间使用空格分开
    void serialize(std::string* out)
    {
#ifdef SELF_SERIALIZE
        // 序列化格式：exitcode_ result_
        *out = std::to_string(exitcode_) + SPACE + std::to_string(result_);
#else
        Json::Value root;
        root["exitcode"] = exitcode_;
        root["result"] = result_;

        Json::FastWriter fastwr;
        *out = fastwr.write(root); // 将序列化后的结果放入
#endif
    }

    // 反序列化
    // 还原成结构体
    bool deserialize(const std::string& in)
    {
#ifdef SELF_SERIALIZE
        size_t pos = in.find(SPACE);
        if (std::string::npos == pos)   return false;

        exitcode_ = atoi(in.substr(0, pos).c_str());
        result_ = atoi(in.substr(pos + SPACE_LEN).c_str());
#else
        Json::Value root;
        Json::Reader rd;
        rd.parse(in, root);

        exitcode_ = root["exitcode"].asInt();
        result_ = root["result"].asInt();
#endif

        return true;
    }

    void debug() { std::cout << "exitcode = " << exitcode_ << " result = " << result_ << " " << std::endl; }
};

// 根据用户输入的内容构建一个请求
const char* ops = "=-*/%";
bool buildRequest(std::string& str, Request* req)
{
    char strtemp[1025];
    snprintf(strtemp, sizeof strtemp, "%s", str.c_str());
    // 有其中一个字符, 那就进行分割
    char* left = strtok(strtemp, ops);
    if (left == nullptr)    return false;
    // 继续从刚刚匹配的位置开始分割
    char* right = strtok(nullptr, ops);
    if (right == nullptr)   return false;

    char op = str[strlen(left)];

    req->leftop_ = atoi(left);
    req->rightop_ = atoi(right);
    req->op_ = op;
    return true;
}